﻿//-----------------------------------------------------------------------
// <copyright file="WallViewModelTest.cs" company="Microsoft">
//     Copyright (c) AGALTIER, Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace ArchiSimple.Windows.Test.ViewModel.PlanObjects
{
    using System;
    using System.Linq;
    using ArchiSimple.Windows.ViewModel;
    using ArchiSimple.Windows.Model;
    using ArchiSimple.Windows.ViewModel.PlanObjects;
    using System.Windows.Media;
    using Xunit;

    /// <summary>
    /// TODO: Provide summary section in the documentation header.
    /// </summary>
    public class WallViewModelTest
    {
        [Fact]
        public void CtorTest()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var wall = new Wall();

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;

                Assert.NotNull(vmWall.Zone);
                Assert.Equal(0, vmWall.Zone.X);
                Assert.Equal(0, vmWall.Zone.Y);
                Assert.Equal(0, vmWall.Zone.Width);
                Assert.Equal(0, vmWall.Zone.Height);
            }
        }

        /// <summary>
        /// Test if begin point know end point when they are add to a wall.
        /// </summary>
        [Fact]
        public void ZoneTest()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point() { X = 0, Y = 10 };
                var point2 = new Point() { X = 100, Y = 90 };
                var wall = new Wall { Begin = point1, End = point2 };

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;

                Assert.NotNull(vmWall.Zone);
                Assert.Equal(0, vmWall.Zone.X);
                Assert.Equal(10, vmWall.Zone.Y);
                Assert.Equal(100, vmWall.Zone.Width);
                Assert.Equal(80, vmWall.Zone.Height);
            }
        }

        /// <summary>
        /// Test if begin point know end point when they are add to a wall.
        /// </summary>
        [Fact]
        public void BeginEndAssociationTest()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point();
                var point2 = new Point();
                var wall = new Wall { Begin = point1, End = point2 };

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;

                Assert.Equal(point1, vmWall.Begin.Current);
                Assert.Equal(1, vmWall.Begin.NextPoints.Count);
                Assert.Equal(vmWall.End, vmWall.Begin.NextPoints[0]);

                Assert.Equal(point2, vmWall.End.Current);
                Assert.Equal(1, vmWall.End.NextPoints.Count);
                Assert.Equal(vmWall.Begin, vmWall.End.NextPoints[0]);
            }
        }

        /// <summary>
        /// Test if begin point know end point when they are add to a wall and the begin point change.
        /// </summary>
        [Fact]
        public void BeginEndAssociationTest_WithBeginPointChange()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point();
                var point2 = new Point();
                var point3 = new Point();
                var wall = new Wall { Begin = point1, End = point2 };

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;
                var vmPoint3 = plan.CreateOrGet(point3) as PointViewModel;

                Assert.Equal(point1, vmWall.Begin.Current);
                Assert.Equal(point2, vmWall.End.Current);

                vmWall.Begin = vmPoint3;

                Assert.Equal(point3, vmWall.Begin.Current);
                Assert.Equal(1, vmWall.Begin.NextPoints.Count);
                Assert.Equal(vmWall.End, vmWall.Begin.NextPoints[0]);

                Assert.Equal(point2, vmWall.End.Current);
                Assert.Equal(1, vmWall.End.NextPoints.Count);
                Assert.Equal(vmWall.Begin, vmWall.End.NextPoints[0]);
            }
        }

        /// <summary>
        /// Test if begin point know end point when they are add to a wall and the end point change.
        /// </summary>
        [Fact]
        public void BeginEndAssociationTest_WithEndPointChange()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point() { X = 10 };
                var point2 = new Point() { X = 20 };
                var point3 = new Point() { X = 30 };
                var wall = new Wall { Begin = point1, End = point2 };

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;
                var vmPoint3 = plan.CreateOrGet(point3) as PointViewModel;

                Assert.Equal(point1, vmWall.Begin.Current);
                Assert.Equal(point2, vmWall.End.Current);

                vmWall.End = vmPoint3;

                Assert.Equal(point1, vmWall.Begin.Current);
                Assert.Equal(1, vmWall.Begin.NextPoints.Count);
                Assert.Equal(vmWall.End, vmWall.Begin.NextPoints[0]);

                Assert.Equal(point3, vmWall.End.Current);
                Assert.Equal(1, vmWall.End.NextPoints.Count);
                Assert.Equal(vmWall.Begin, vmWall.End.NextPoints[0]);
            }
        }

        /// <summary>
        /// Test if begin point know end point when they are add to a wall and the begin point change.
        /// </summary>
        [Fact]
        public void BeginEndAssociationTest_WithThreeWall()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point() { X = 10 };
                var point2 = new Point() { X = 20 };
                var point3 = new Point() { X = 30 };
                var point4 = new Point() { X = 40 };
                var wall1 = new Wall { Begin = point1, End = point2 };
                var wall2 = new Wall { Begin = point2, End = point3 };
                var wall3 = new Wall { Begin = point4, End = point3 };

                var vmWall1 = plan.CreateOrGet(wall1) as WallViewModel;
                var vmWall2 = plan.CreateOrGet(wall2) as WallViewModel;
                var vmWall3 = plan.CreateOrGet(wall3) as WallViewModel;

                Assert.Equal(1, vmWall1.Begin.NextPoints.Count);
                Assert.Equal(point2, vmWall1.Begin.NextPoints[0].Current);

                Assert.Equal(2, vmWall1.End.NextPoints.Count);
                Assert.Equal(point1, vmWall1.End.NextPoints[0].Current);
                Assert.Equal(point3, vmWall1.End.NextPoints[1].Current);
                Assert.Equal(vmWall1.End.Current, vmWall2.Begin.Current);

                Assert.Equal(2, vmWall2.End.NextPoints.Count);
                Assert.Equal(point2, vmWall2.End.NextPoints[0].Current);
                Assert.Equal(point4, vmWall2.End.NextPoints[1].Current);
                Assert.Equal(vmWall2.End.Current, vmWall3.End.Current);

                Assert.Equal(1, vmWall3.Begin.NextPoints.Count);
                Assert.Equal(point3, vmWall3.Begin.NextPoints[0].Current);
            }
        }

        [Fact]
        public void WallGeometryTest()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();

                var point1 = new Point() { X = 10, Y = 10 };
                var point2 = new Point() { X = 20, Y = 20 };
                var wall = new Wall { Begin = point1, End = point2 };

                var vmWall = plan.CreateOrGet(wall) as WallViewModel;

                var figure = vmWall.WallGeometry;

                Assert.NotNull(figure);
                Assert.Equal(1, figure.Segments.Count);
                Assert.IsType(typeof(PolyLineSegment), figure.Segments[0]);
                var segment = figure.Segments[0] as PolyLineSegment;
                Assert.Equal(1, segment.Points.Count);
                Assert.Equal(10, figure.StartPoint.X);
                Assert.Equal(10, figure.StartPoint.Y);
                Assert.Equal(20, segment.Points[0].X);
                Assert.Equal(20, segment.Points[0].Y);

                vmWall.Begin.X = 30;
                Assert.Equal(30, figure.StartPoint.X);
                Assert.Equal(10, figure.StartPoint.Y);
                Assert.Equal(20, segment.Points[0].X);
                Assert.Equal(20, segment.Points[0].Y);

                vmWall.Begin.Y = 40;
                Assert.Equal(30, figure.StartPoint.X);
                Assert.Equal(40, figure.StartPoint.Y);
                Assert.Equal(20, segment.Points[0].X);
                Assert.Equal(20, segment.Points[0].Y);

                vmWall.End.X = 50;
                Assert.Equal(30, figure.StartPoint.X);
                Assert.Equal(40, figure.StartPoint.Y);
                Assert.Equal(50, segment.Points[0].X);
                Assert.Equal(20, segment.Points[0].Y);

                vmWall.End.Y = 60;
                Assert.Equal(30, figure.StartPoint.X);
                Assert.Equal(40, figure.StartPoint.Y);
                Assert.Equal(50, segment.Points[0].X);
                Assert.Equal(60, segment.Points[0].Y);
            }
        }

        [Fact]
        public void DeleteWall_WithOneWall()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 100);

                Assert.Equal(3, plan.PlanObjects.Count);
                Assert.Equal(3, planModel.PlanObjects.Count);
                Assert.IsType<WallViewModel>(plan.PlanObjects[0]);

                var wall = plan.PlanObjects[0] as WallViewModel;
                wall.Delete();
                Assert.Equal(0, plan.PlanObjects.Count);
                Assert.Equal(0, planModel.PlanObjects.Count);
            }
        }

        [Fact]
        public void DeleteWall_WithTwoWall()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 100);
                plan.AddWall(100, 100, 100, 200);

                Assert.Equal(5, plan.PlanObjects.Count);
                Assert.Equal(5, planModel.PlanObjects.Count);
                Assert.IsType<WallViewModel>(plan.PlanObjects[0]);

                var wall = plan.PlanObjects[0] as WallViewModel;

                wall.Delete();
                Assert.Equal(3, plan.PlanObjects.Count);
                Assert.Equal(3, planModel.PlanObjects.Count);
                Assert.IsType<WallViewModel>(plan.PlanObjects[1]);
                wall = plan.PlanObjects[1] as WallViewModel;

                Assert.Equal(100, wall.Begin.X);
                Assert.Equal(100, wall.Begin.Y);
                Assert.Equal(100, wall.End.X);
                Assert.Equal(200, wall.End.Y);
            }
        }

        [Fact]
        public void DeleteWall_WithRoom()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 0);
                plan.AddWall(100, 0, 100, 100);
                plan.AddWall(100, 100, 0, 100);
                plan.AddWall(0, 100, 0, 0);

                Assert.Equal(9, plan.PlanObjects.Count);
                Assert.Equal(1, plan.PlanObjects.OfType<RoomViewModel>().Count());

                var wall = plan.PlanObjects.OfType<WallViewModel>().Last();

                wall.Delete();

                Assert.Equal(7, plan.PlanObjects.Count);
                Assert.Equal(0, plan.PlanObjects.OfType<RoomViewModel>().Count());
                Assert.Equal(3, plan.PlanObjects.OfType<WallViewModel>().Count());
                Assert.Equal(4, plan.PlanObjects.OfType<PointViewModel>().Count());
            }
        }


        [Fact]
        public void DeleteWall_WithRooms()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 0);
                plan.AddWall(100, 0, 100, 100);
                plan.AddWall(100, 100, 0, 100);
                plan.AddWall(0, 100, 0, 0);
                plan.AddWall(50, 0, 50, 100);

                Assert.Equal(15, plan.PlanObjects.Count);
                Assert.Equal(2, plan.PlanObjects.OfType<RoomViewModel>().Count());

                var wall = (from w in plan.PlanObjects.OfType<WallViewModel>()
                            where w.Begin.X == 100
                            && w.Begin.Y == 0
                            && w.End.X == 100
                            && w.End.Y == 100
                            select w).FirstOrDefault();

                wall.Delete();

                Assert.Equal(13, plan.PlanObjects.Count);
                Assert.Equal(1, plan.PlanObjects.OfType<RoomViewModel>().Count());
                Assert.Equal(6, plan.PlanObjects.OfType<WallViewModel>().Count());
                Assert.Equal(6, plan.PlanObjects.OfType<PointViewModel>().Count());

            }
        }

        [Fact]
        public void DeletePoint_WithRooms2()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 0);
                plan.AddWall(100, 0, 100, 100);
                plan.AddWall(100, 100, 0, 100);
                plan.AddWall(0, 100, 0, 0);
                plan.AddWall(50, 0, 50, 100);

                Assert.Equal(15, plan.PlanObjects.Count);
                Assert.Equal(2, plan.PlanObjects.OfType<RoomViewModel>().Count());

                var wall = (from w in plan.PlanObjects.OfType<WallViewModel>()
                            where w.Begin.X == 50
                            && w.Begin.Y == 0
                            && w.End.X == 50
                            && w.End.Y == 100
                            select w).FirstOrDefault();

                wall.Delete();

                Assert.Equal(13, plan.PlanObjects.Count);
                Assert.Equal(1, plan.PlanObjects.OfType<RoomViewModel>().Count());
                Assert.Equal(6, plan.PlanObjects.OfType<WallViewModel>().Count());
                Assert.Equal(6, plan.PlanObjects.OfType<PointViewModel>().Count());

                var room = plan.PlanObjects.OfType<RoomViewModel>().First();
                Assert.Equal(6, room.Points.Count());
            }
        }

        [Fact]
        public void ResizeWall()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 100);

                var wall = plan.PlanObjects[0] as WallViewModel;

                wall.SizeMode = WallViewModel.ExtendMode.Begin;
                wall.Size = 50;
                Assert.Equal(50, wall.Size);
                wall.Size = 20;
                Assert.Equal(20, wall.Size);
                wall.Size = 100;
                Assert.Equal(100, wall.Size);
                wall.Size = 0;
                Assert.Equal(100, wall.Size);
                wall.Size = 200;
                Assert.Equal(200, wall.Size);

                Assert.Equal(141, (int)wall.End.X);
                Assert.Equal(141, (int)wall.End.Y);
            }
        }

        [Fact]
        public void ResizeWall2()
        {
            using (new LocatorContext())
            {
                var plan = Locator.Locate<PlanViewModel>(null);
                plan.Init();
                var planModel = new Plan();
                plan.LoadPlanMessage(new Message.LoadPlanMessage { Plan = planModel });

                plan.AddWall(0, 0, 100, 50);

                var wall = plan.PlanObjects[0] as WallViewModel;

                wall.SizeMode = WallViewModel.ExtendMode.Begin;
                int s = (int)Math.Sqrt(50 * 50 + 25 * 25);
                wall.Size = s;
                Assert.Equal(s, wall.Size);

                Assert.Equal(49, (int)wall.End.X);
                Assert.Equal(24, (int)wall.End.Y);
            }
        }
    }
}
